<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha256-CTSx/A06dm1B063156EVh15m6Y67pAjZZaQc89LLSrU=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.24/fancybox/fancybox.css" integrity="sha256-vQkngPS8jiHHH0I6ABTZroZk8NPZ7b+MUReOFE9UsXQ=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"rjyblog.gitee.io","root":"/","images":"/images","scheme":"Pisces","darkmode":false,"version":"8.18.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":null},"fold":{"enable":false,"height":500},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="本文基于Java的ReentrantLock类从源码角度分析公平锁和非公平锁的实现原理">
<meta property="og:type" content="article">
<meta property="og:title" content="Java 公平锁和非公平锁">
<meta property="og:url" content="https://rjyblog.gitee.io/posts/c7038aa0.html">
<meta property="og:site_name" content="任建勇的博客">
<meta property="og:description" content="本文基于Java的ReentrantLock类从源码角度分析公平锁和非公平锁的实现原理">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2023-09-02T03:59:43.000Z">
<meta property="article:modified_time" content="2023-09-04T03:22:46.163Z">
<meta property="article:author" content="Jason">
<meta property="article:tag" content="Java">
<meta name="twitter:card" content="summary">


<link rel="canonical" href="https://rjyblog.gitee.io/posts/c7038aa0.html">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://rjyblog.gitee.io/posts/c7038aa0.html","path":"posts/c7038aa0.html","title":"Java 公平锁和非公平锁"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>Java 公平锁和非公平锁 | 任建勇的博客</title>
  








  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">任建勇的博客</p>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%85%AC%E5%B9%B3%E9%94%81%E5%8A%A0%E9%94%81"><span class="nav-text">公平锁加锁</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%9D%9E%E5%85%AC%E5%B9%B3%E9%94%81%E5%8A%A0%E9%94%81"><span class="nav-text">非公平锁加锁</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%87%8A%E6%94%BE%E9%94%81"><span class="nav-text">释放锁</span></a></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Jason"
      src="/images/avatar.png">
  <p class="site-author-name" itemprop="name">Jason</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">66</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">13</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">23</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://rjyblog.gitee.io/posts/c7038aa0.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="Jason">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="任建勇的博客">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="Java 公平锁和非公平锁 | 任建勇的博客">
      <meta itemprop="description" content="本文基于Java的ReentrantLock类从源码角度分析公平锁和非公平锁的实现原理">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Java 公平锁和非公平锁
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-09-02 11:59:43" itemprop="dateCreated datePublished" datetime="2023-09-02T11:59:43+08:00">2023-09-02</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-09-04 11:22:46" itemprop="dateModified" datetime="2023-09-04T11:22:46+08:00">2023-09-04</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a>
        </span>
    </span>

  
</div>

            <div class="post-description">本文基于Java的ReentrantLock类从源码角度分析公平锁和非公平锁的实现原理</div>
        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><p>公平锁：指的是多个线程等待同一个锁时，等待时间最长的线程将会优先获取到锁。但是，这也会导致当线程尝试获取锁时，很大概率会进入阻塞状态，有很高的状态切换成本，因此，会降低吞吐量和执行效率。</p>
<p>非公平锁：不会保证一个特定获取到锁的顺序。当线程尝试获取锁时，会优先通过CAS尝试获取锁，如果失败了才会进入等待队列。非公平锁的执行效率更高，因为线程尝试获取锁的时候，如果能够直接获取到锁，可以节省线程的上下文切换带来的时间和性能上的开销。但是，可能会导致有的线程永远也获取不到锁。</p>
<p>Java中的<code>synchronized</code>是非公平锁，<code>ReentrantLock</code>默认也是非公平锁，并且是可重入的。<code>ReentrantLock</code>则可以通过<code>fair</code>来设置为公平锁。下面是<code>ReentrantLock</code>的类图结构：</p>
<?xml version="1.0" encoding="us-ascii" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="386px" preserveAspectRatio="none" style="width:345px;height:386px;background:#FFFFFF;" version="1.1" viewBox="0 0 345 386" width="345px" zoomAndPan="magnify"><defs/><g><!--class AbstractOwnableSynchronizer--><g id="elem_AbstractOwnableSynchronizer"><rect codeLine="1" fill="#F1F1F1" height="48" id="AbstractOwnableSynchronizer" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="246" x="92" y="7"/><ellipse cx="107" cy="23" fill="#A9DCDF" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M109.0781,24.8125 L109.4688,25.7969 L109.0781,25.7969 C108.625,25.7969 108.5156,25.8125 108.3594,25.9219 C108.1094,26.0781 107.9531,26.3594 107.9531,26.6563 C107.9531,26.9219 108.0938,27.1719 108.3125,27.3281 C108.4531,27.4531 108.6563,27.5 109.0781,27.5 L111.4375,27.5 C111.7969,27.5 112.0156,27.4688 112.1563,27.375 C112.4063,27.2344 112.5625,26.9375 112.5625,26.6563 C112.5625,26.375 112.4219,26.125 112.2031,25.9688 C112.0313,25.8281 111.875,25.7969 111.4063,25.7969 L108.0156,17.5938 L104.3438,17.5938 C103.8906,17.5938 103.7656,17.6094 103.6094,17.7031 C103.3594,17.875 103.2031,18.1563 103.2031,18.4375 C103.2031,18.7188 103.3438,18.9688 103.5625,19.1406 C103.7344,19.25 103.9063,19.2813 104.3438,19.2813 L105.4219,19.2813 L102.7813,25.7969 C102.3594,25.7969 102.2031,25.8125 102.0469,25.9219 C101.7969,26.0781 101.6406,26.3594 101.6406,26.6563 C101.6406,27.2188 102.0156,27.5 102.7656,27.5 L105.0313,27.5 C105.3906,27.5 105.6094,27.4688 105.7344,27.375 C106,27.2344 106.1406,26.9375 106.1406,26.6563 C106.1406,26.375 106.0156,26.125 105.7969,25.9531 C105.625,25.8281 105.4844,25.7969 105.0313,25.7969 L104.6406,25.7969 L105.0313,24.8125 L109.0781,24.8125 Z M108.375,23.1094 L105.7031,23.1094 L107.0469,19.8438 L108.375,23.1094 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="214" x="121" y="27.8467">AbstractOwnableSynchronizer</text><line style="stroke:#181818;stroke-width:0.5;" x1="93" x2="337" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="93" x2="337" y1="47" y2="47"/></g><!--class AbstractQueuedSynchronizer--><g id="elem_AbstractQueuedSynchronizer"><rect codeLine="2" fill="#F1F1F1" height="48" id="AbstractQueuedSynchronizer" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="240" x="95" y="115"/><ellipse cx="110" cy="131" fill="#A9DCDF" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M112.0781,132.8125 L112.4688,133.7969 L112.0781,133.7969 C111.625,133.7969 111.5156,133.8125 111.3594,133.9219 C111.1094,134.0781 110.9531,134.3594 110.9531,134.6563 C110.9531,134.9219 111.0938,135.1719 111.3125,135.3281 C111.4531,135.4531 111.6563,135.5 112.0781,135.5 L114.4375,135.5 C114.7969,135.5 115.0156,135.4688 115.1563,135.375 C115.4063,135.2344 115.5625,134.9375 115.5625,134.6563 C115.5625,134.375 115.4219,134.125 115.2031,133.9688 C115.0313,133.8281 114.875,133.7969 114.4063,133.7969 L111.0156,125.5938 L107.3438,125.5938 C106.8906,125.5938 106.7656,125.6094 106.6094,125.7031 C106.3594,125.875 106.2031,126.1563 106.2031,126.4375 C106.2031,126.7188 106.3438,126.9688 106.5625,127.1406 C106.7344,127.25 106.9063,127.2813 107.3438,127.2813 L108.4219,127.2813 L105.7813,133.7969 C105.3594,133.7969 105.2031,133.8125 105.0469,133.9219 C104.7969,134.0781 104.6406,134.3594 104.6406,134.6563 C104.6406,135.2188 105.0156,135.5 105.7656,135.5 L108.0313,135.5 C108.3906,135.5 108.6094,135.4688 108.7344,135.375 C109,135.2344 109.1406,134.9375 109.1406,134.6563 C109.1406,134.375 109.0156,134.125 108.7969,133.9531 C108.625,133.8281 108.4844,133.7969 108.0313,133.7969 L107.6406,133.7969 L108.0313,132.8125 L112.0781,132.8125 Z M111.375,131.1094 L108.7031,131.1094 L110.0469,127.8438 L111.375,131.1094 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="208" x="124" y="135.8467">AbstractQueuedSynchronizer</text><line style="stroke:#181818;stroke-width:0.5;" x1="96" x2="334" y1="147" y2="147"/><line style="stroke:#181818;stroke-width:0.5;" x1="96" x2="334" y1="155" y2="155"/></g><!--class Sync--><g id="elem_Sync"><rect codeLine="3" fill="#F1F1F1" height="48" id="Sync" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="66" x="182" y="223"/><ellipse cx="197" cy="239" fill="#A9DCDF" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M199.0781,240.8125 L199.4688,241.7969 L199.0781,241.7969 C198.625,241.7969 198.5156,241.8125 198.3594,241.9219 C198.1094,242.0781 197.9531,242.3594 197.9531,242.6563 C197.9531,242.9219 198.0938,243.1719 198.3125,243.3281 C198.4531,243.4531 198.6563,243.5 199.0781,243.5 L201.4375,243.5 C201.7969,243.5 202.0156,243.4688 202.1563,243.375 C202.4063,243.2344 202.5625,242.9375 202.5625,242.6563 C202.5625,242.375 202.4219,242.125 202.2031,241.9688 C202.0313,241.8281 201.875,241.7969 201.4063,241.7969 L198.0156,233.5938 L194.3438,233.5938 C193.8906,233.5938 193.7656,233.6094 193.6094,233.7031 C193.3594,233.875 193.2031,234.1563 193.2031,234.4375 C193.2031,234.7188 193.3438,234.9688 193.5625,235.1406 C193.7344,235.25 193.9063,235.2813 194.3438,235.2813 L195.4219,235.2813 L192.7813,241.7969 C192.3594,241.7969 192.2031,241.8125 192.0469,241.9219 C191.7969,242.0781 191.6406,242.3594 191.6406,242.6563 C191.6406,243.2188 192.0156,243.5 192.7656,243.5 L195.0313,243.5 C195.3906,243.5 195.6094,243.4688 195.7344,243.375 C196,243.2344 196.1406,242.9375 196.1406,242.6563 C196.1406,242.375 196.0156,242.125 195.7969,241.9531 C195.625,241.8281 195.4844,241.7969 195.0313,241.7969 L194.6406,241.7969 L195.0313,240.8125 L199.0781,240.8125 Z M198.375,239.1094 L195.7031,239.1094 L197.0469,235.8438 L198.375,239.1094 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="34" x="211" y="243.8467">Sync</text><line style="stroke:#181818;stroke-width:0.5;" x1="183" x2="247" y1="255" y2="255"/><line style="stroke:#181818;stroke-width:0.5;" x1="183" x2="247" y1="263" y2="263"/></g><!--class ReentrantLock--><g id="elem_ReentrantLock"><rect codeLine="4" fill="#ADD8E6" height="48" id="ReentrantLock" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="140" x="7" y="223"/><ellipse cx="22" cy="239" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M24.3438,234.6719 C23.4063,234.2344 22.8125,234.0938 21.9375,234.0938 C19.3125,234.0938 17.3125,236.1719 17.3125,238.8906 L17.3125,240.0156 C17.3125,242.5938 19.4219,244.4844 22.3125,244.4844 C23.5313,244.4844 24.6875,244.1875 25.4375,243.6406 C26.0156,243.2344 26.3438,242.7813 26.3438,242.3906 C26.3438,241.9375 25.9531,241.5469 25.4844,241.5469 C25.2656,241.5469 25.0625,241.625 24.875,241.8125 C24.4219,242.2969 24.4219,242.2969 24.2344,242.3906 C23.8125,242.6563 23.125,242.7813 22.3594,242.7813 C20.3125,242.7813 19.0156,241.6875 19.0156,239.9844 L19.0156,238.8906 C19.0156,237.1094 20.2656,235.7969 22,235.7969 C22.5781,235.7969 23.1875,235.9531 23.6563,236.2031 C24.1406,236.4844 24.3125,236.7031 24.4063,237.1094 C24.4688,237.5156 24.5,237.6406 24.6406,237.7656 C24.7813,237.9063 25.0156,238.0156 25.2344,238.0156 C25.5,238.0156 25.7656,237.875 25.9375,237.6563 C26.0469,237.5 26.0781,237.3125 26.0781,236.8906 L26.0781,235.4688 C26.0781,235.0313 26.0625,234.9063 25.9688,234.75 C25.8125,234.4844 25.5313,234.3438 25.2344,234.3438 C24.9375,234.3438 24.7344,234.4375 24.5156,234.75 L24.3438,234.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="108" x="36" y="243.8467">ReentrantLock</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="146" y1="255" y2="255"/><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="146" y1="263" y2="263"/></g><!--class NonfairSync--><g id="elem_NonfairSync"><rect fill="#F1F1F1" height="48" id="NonfairSync" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="118" x="86" y="331"/><ellipse cx="101" cy="347" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M103.3438,342.6719 C102.4063,342.2344 101.8125,342.0938 100.9375,342.0938 C98.3125,342.0938 96.3125,344.1719 96.3125,346.8906 L96.3125,348.0156 C96.3125,350.5938 98.4219,352.4844 101.3125,352.4844 C102.5313,352.4844 103.6875,352.1875 104.4375,351.6406 C105.0156,351.2344 105.3438,350.7813 105.3438,350.3906 C105.3438,349.9375 104.9531,349.5469 104.4844,349.5469 C104.2656,349.5469 104.0625,349.625 103.875,349.8125 C103.4219,350.2969 103.4219,350.2969 103.2344,350.3906 C102.8125,350.6563 102.125,350.7813 101.3594,350.7813 C99.3125,350.7813 98.0156,349.6875 98.0156,347.9844 L98.0156,346.8906 C98.0156,345.1094 99.2656,343.7969 101,343.7969 C101.5781,343.7969 102.1875,343.9531 102.6563,344.2031 C103.1406,344.4844 103.3125,344.7031 103.4063,345.1094 C103.4688,345.5156 103.5,345.6406 103.6406,345.7656 C103.7813,345.9063 104.0156,346.0156 104.2344,346.0156 C104.5,346.0156 104.7656,345.875 104.9375,345.6563 C105.0469,345.5 105.0781,345.3125 105.0781,344.8906 L105.0781,343.4688 C105.0781,343.0313 105.0625,342.9063 104.9688,342.75 C104.8125,342.4844 104.5313,342.3438 104.2344,342.3438 C103.9375,342.3438 103.7344,342.4375 103.5156,342.75 L103.3438,342.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="86" x="115" y="351.8467">NonfairSync</text><line style="stroke:#181818;stroke-width:0.5;" x1="87" x2="203" y1="363" y2="363"/><line style="stroke:#181818;stroke-width:0.5;" x1="87" x2="203" y1="371" y2="371"/></g><!--class FairSync--><g id="elem_FairSync"><rect fill="#F1F1F1" height="48" id="FairSync" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="92" x="239" y="331"/><ellipse cx="254" cy="347" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M256.3438,342.6719 C255.4063,342.2344 254.8125,342.0938 253.9375,342.0938 C251.3125,342.0938 249.3125,344.1719 249.3125,346.8906 L249.3125,348.0156 C249.3125,350.5938 251.4219,352.4844 254.3125,352.4844 C255.5313,352.4844 256.6875,352.1875 257.4375,351.6406 C258.0156,351.2344 258.3438,350.7813 258.3438,350.3906 C258.3438,349.9375 257.9531,349.5469 257.4844,349.5469 C257.2656,349.5469 257.0625,349.625 256.875,349.8125 C256.4219,350.2969 256.4219,350.2969 256.2344,350.3906 C255.8125,350.6563 255.125,350.7813 254.3594,350.7813 C252.3125,350.7813 251.0156,349.6875 251.0156,347.9844 L251.0156,346.8906 C251.0156,345.1094 252.2656,343.7969 254,343.7969 C254.5781,343.7969 255.1875,343.9531 255.6563,344.2031 C256.1406,344.4844 256.3125,344.7031 256.4063,345.1094 C256.4688,345.5156 256.5,345.6406 256.6406,345.7656 C256.7813,345.9063 257.0156,346.0156 257.2344,346.0156 C257.5,346.0156 257.7656,345.875 257.9375,345.6563 C258.0469,345.5 258.0781,345.3125 258.0781,344.8906 L258.0781,343.4688 C258.0781,343.0313 258.0625,342.9063 257.9688,342.75 C257.8125,342.4844 257.5313,342.3438 257.2344,342.3438 C256.9375,342.3438 256.7344,342.4375 256.5156,342.75 L256.3438,342.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="60" x="268" y="351.8467">FairSync</text><line style="stroke:#181818;stroke-width:0.5;" x1="240" x2="330" y1="363" y2="363"/><line style="stroke:#181818;stroke-width:0.5;" x1="240" x2="330" y1="371" y2="371"/></g><!--reverse link ReentrantLock to Sync--><g id="link_ReentrantLock_Sync"><path codeLine="5" d="M159.078,247 C170.664,247 170.249,247 181.835,247 " fill="none" id="ReentrantLock-backto-Sync" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="147.078,247,153.078,251,159.078,247,153.078,243,147.078,247" style="stroke:#181818;stroke-width:1.0;"/></g><!--reverse link AbstractOwnableSynchronizer to AbstractQueuedSynchronizer--><g id="link_AbstractOwnableSynchronizer_AbstractQueuedSynchronizer"><path codeLine="6" d="M215,73 C215,90.658 215,96.941 215,114.678 " fill="none" id="AbstractOwnableSynchronizer-backto-AbstractQueuedSynchronizer" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="215,55,209,73,221,73,215,55" style="stroke:#181818;stroke-width:1.0;"/></g><!--reverse link AbstractQueuedSynchronizer to Sync--><g id="link_AbstractQueuedSynchronizer_Sync"><path codeLine="7" d="M215,181 C215,198.658 215,204.941 215,222.678 " fill="none" id="AbstractQueuedSynchronizer-backto-Sync" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="215,163,209,181,221,181,215,163" style="stroke:#181818;stroke-width:1.0;"/></g><!--reverse link Sync to NonfairSync--><g id="link_Sync_NonfairSync"><path codeLine="8" d="M189.892,286.0204 C178.231,303.6788 172.115,312.9408 160.401,330.6784 " fill="none" id="Sync-backto-NonfairSync" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="199.811,271,184.8852,282.7141,194.8988,289.3268,199.811,271" style="stroke:#181818;stroke-width:1.0;"/></g><!--reverse link Sync to FairSync--><g id="link_Sync_FairSync"><path codeLine="9" d="M240.108,286.0204 C251.769,303.6788 257.885,312.9408 269.599,330.6784 " fill="none" id="Sync-backto-FairSync" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="230.189,271,235.1012,289.3268,245.1148,282.7141,230.189,271" style="stroke:#181818;stroke-width:1.0;"/></g><!--SRC=[IqmgBYbAJ2vHS8Go_Clp4fDoKeChyv8pYlBpCgjIYxWIqHK5bgQMfgPWLmCIvKhEIImkLWXAJSq32kQL-EGdPoievsIcPvGavPIcSg5AQEb2DE4sNK6tj42tnWwl8q4ST7LOt0bMPbEZgwlWbv-NbfXP1BOQ8Ue65G80]--></g></svg>

<h2 id="公平锁加锁"><a href="#公平锁加锁" class="headerlink" title="公平锁加锁"></a>公平锁加锁</h2><p>公平锁加锁过程的方法调用：<code>ReentrantLock#lock()</code> &rarr; <code>ReentrantLock.FairSync#lock()</code> &rarr; <code>AbstractQueuedSynchronizer#acquire(1)</code>。下面看下acquire的代码实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 【AbstractQueuedSynchronizer.java】</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">acquire</span><span class="params">(<span class="type">int</span> arg)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (!tryAcquire(arg) &amp;&amp;</span><br><span class="line">            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))</span><br><span class="line">            selfInterrupt();</span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">// 【ReentrantLock.java】</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">FairSync</span> <span class="keyword">extends</span> <span class="title class_">Sync</span> &#123;</span><br><span class="line">        ......</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * Fair version of tryAcquire.  Don&#x27;t grant access unless</span></span><br><span class="line"><span class="comment">         * recursive call or no waiters or is first.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="comment">// 只有锁未被锁定、锁重入或者等待队列中没有前辈的情况才会获取成功</span></span><br><span class="line">        <span class="keyword">protected</span> <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">tryAcquire</span><span class="params">(<span class="type">int</span> acquires)</span> &#123;</span><br><span class="line">            <span class="keyword">final</span> <span class="type">Thread</span> <span class="variable">current</span> <span class="operator">=</span> Thread.currentThread();</span><br><span class="line">            <span class="type">int</span> <span class="variable">c</span> <span class="operator">=</span> getState();</span><br><span class="line">            <span class="keyword">if</span> (c == <span class="number">0</span>) &#123; <span class="comment">//state为0表示当前是未被锁定状态</span></span><br><span class="line">                <span class="keyword">if</span> (!hasQueuedPredecessors() &amp;&amp; <span class="comment">//判断等待队列是否有排在自己前面的线程</span></span><br><span class="line">                    compareAndSetState(<span class="number">0</span>, acquires)) &#123; <span class="comment">//通过CAS设置锁定状态</span></span><br><span class="line">                    setExclusiveOwnerThread(current); <span class="comment">//独占线程设置为自己</span></span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>; <span class="comment">//加锁成功</span></span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (current == getExclusiveOwnerThread()) &#123;</span><br><span class="line">                <span class="comment">// 锁的重入，状态加1</span></span><br><span class="line">                <span class="type">int</span> <span class="variable">nextc</span> <span class="operator">=</span> c + acquires;</span><br><span class="line">                <span class="keyword">if</span> (nextc &lt; <span class="number">0</span>)</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&quot;Maximum lock count exceeded&quot;</span>);</span><br><span class="line">                setState(nextc);</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">true</span>; <span class="comment">//加锁成功</span></span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>; <span class="comment">//加锁失败</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">// 【AbstractQueuedSynchronizer.java】</span></span><br><span class="line"><span class="comment">// addWaiter的作用就是将当前线程添加到等待队列的队尾</span></span><br><span class="line">    <span class="keyword">private</span> Node <span class="title function_">addWaiter</span><span class="params">(Node mode)</span> &#123;</span><br><span class="line">        <span class="type">Node</span> <span class="variable">node</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Node</span>(Thread.currentThread(), mode);</span><br><span class="line">        <span class="comment">// Try the fast path of enq; backup to full enq on failure</span></span><br><span class="line">        <span class="type">Node</span> <span class="variable">pred</span> <span class="operator">=</span> tail;</span><br><span class="line">        <span class="keyword">if</span> (pred != <span class="literal">null</span>) &#123;</span><br><span class="line">            node.prev = pred;</span><br><span class="line">            <span class="keyword">if</span> (compareAndSetTail(pred, node)) &#123;</span><br><span class="line">                pred.next = node;</span><br><span class="line">                <span class="keyword">return</span> node;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        enq(node);</span><br><span class="line">        <span class="keyword">return</span> node;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">acquireQueued</span><span class="params">(<span class="keyword">final</span> Node node, <span class="type">int</span> arg)</span> &#123;</span><br><span class="line">        <span class="type">boolean</span> <span class="variable">failed</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="type">boolean</span> <span class="variable">interrupted</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line">            <span class="keyword">for</span> (;;) &#123; <span class="comment">//循环</span></span><br><span class="line">                <span class="keyword">final</span> <span class="type">Node</span> <span class="variable">p</span> <span class="operator">=</span> node.predecessor();</span><br><span class="line">                <span class="keyword">if</span> (p == head &amp;&amp; tryAcquire(arg)) &#123;</span><br><span class="line">                    <span class="comment">// 请求锁的当前线程排在了队首，且获取锁成功</span></span><br><span class="line">                    setHead(node); <span class="comment">//设置为head，所以head是持有锁的线程</span></span><br><span class="line">                    p.next = <span class="literal">null</span>; <span class="comment">// help GC</span></span><br><span class="line">                    failed = <span class="literal">false</span>;</span><br><span class="line">                    <span class="keyword">return</span> interrupted;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (shouldParkAfterFailedAcquire(p, node) &amp;&amp;</span><br><span class="line">                    parkAndCheckInterrupt()) <span class="comment">//进入blocked状态</span></span><br><span class="line">                    interrupted = <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (failed)</span><br><span class="line">                cancelAcquire(node);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<?xml version="1.0" encoding="us-ascii" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="1064px" preserveAspectRatio="none" style="width:420px;height:1064px;background:#FFFFFF;" version="1.1" viewBox="0 0 420 1064" width="420px" zoomAndPan="magnify"><defs/><g><ellipse cx="217.5" cy="20" fill="#222222" rx="10" ry="10" style="stroke:#222222;stroke-width:1.0;"/><rect fill="none" height="491.2339" style="stroke:#000000;stroke-width:1.5;" width="398" x="11" y="40"/><path d="M106,40 L106,49.2969 L96,59.2969 L11,59.2969 " fill="none" style="stroke:#000000;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="85" x="14" y="53.9951">tryAcquire()</text><polygon fill="#F1F1F1" points="42.5,79.2969,161.5,79.2969,173.5,91.2969,161.5,103.2969,42.5,103.2969,30.5,91.2969,42.5,79.2969" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="21" x="106" y="113.5073">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="119" x="42.5" y="95.105">&#38145;&#26410;&#34987;&#38145;&#23450; state==0?</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="158" x="23" y="183.4097"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="138" x="33" y="204.5483">CAS&#35774;&#32622;state&#20026;&#38145;&#23450;&#29366;&#24577;</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="152" x="26" y="300.7808"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="132" x="36" y="321.9194">&#24403;&#21069;&#32447;&#31243;&#35774;&#32622;&#20026;&#29420;&#21344;&#32447;&#31243;</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="68" x="68" y="357.2651"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="48" x="78" y="378.4038">&#21152;&#38145;&#25104;&#21151;</text><ellipse cx="102" cy="422.2339" fill="none" rx="11" ry="11" style="stroke:#222222;stroke-width:1.0;"/><ellipse cx="102" cy="422.2339" fill="#222222" rx="6" ry="6" style="stroke:#222222;stroke-width:1.0;"/><polygon fill="#F1F1F1" points="65,252.3784,139,252.3784,151,264.3784,139,276.3784,65,276.3784,53,264.3784,65,252.3784" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="21" x="106" y="286.5889">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="74" x="65" y="268.1865">CAS&#35774;&#32622;&#25104;&#21151;?</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="14" x="151" y="261.7842">no</text><polygon fill="#F1F1F1" points="52.5,135.0073,151.5,135.0073,163.5,147.0073,151.5,159.0073,52.5,159.0073,40.5,147.0073,52.5,135.0073" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="14" x="106" y="169.2178">no</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="99" x="52.5" y="150.8154">&#26377;&#20854;&#20182;&#32447;&#31243;&#27491;&#22312;&#25490;&#38431;</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="21" x="163.5" y="144.4131">yes</text><polygon fill="#F1F1F1" points="102,475.2339,114,487.2339,102,499.2339,90,487.2339,102,475.2339" style="stroke:#181818;stroke-width:0.5;"/><polygon fill="#F1F1F1" points="268,79.2969,367,79.2969,379,91.2969,367,103.2969,268,103.2969,256,91.2969,268,79.2969" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="21" x="321.5" y="113.5073">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="99" x="268" y="95.105">&#24403;&#21069;&#32447;&#31243;&#24050;&#32463;&#25345;&#26377;&#38145;</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="14" x="242" y="88.7026">no</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="69" x="283" y="135.0073"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="49" x="293" y="156.146">state&#21152;1</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="68" x="283.5" y="203.9761"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="48" x="293.5" y="225.1147">&#21152;&#38145;&#25104;&#21151;</text><ellipse cx="317.5" cy="283.9448" fill="none" rx="11" ry="11" style="stroke:#222222;stroke-width:1.0;"/><ellipse cx="317.5" cy="283.9448" fill="#222222" rx="6" ry="6" style="stroke:#222222;stroke-width:1.0;"/><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="128" x="153.5" y="551.2339"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="108" x="163.5" y="572.3726">&#28155;&#21152;&#21040;&#31561;&#24453;&#38431;&#21015;&#38431;&#23614;</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="140" x="147.5" y="697.605"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="120" x="157.5" y="718.7437">&#20877;&#27425;&#35843;&#29992;tryAcquire()</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="134" x="150.5" y="799.9761"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="114" x="160.5" y="821.1147">&#24403;&#21069;&#33410;&#28857;&#35774;&#32622;&#20026;head</text><ellipse cx="217.5" cy="877.4604" fill="none" rx="11" ry="11" style="stroke:#222222;stroke-width:1.0;"/><ellipse cx="217.5" cy="877.4604" fill="#222222" rx="6" ry="6" style="stroke:#222222;stroke-width:1.0;"/><polygon fill="#F1F1F1" points="161,751.5737,274,751.5737,286,763.5737,274,775.5737,161,775.5737,149,763.5737,161,751.5737" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="21" x="221.5" y="785.7842">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="113" x="161" y="767.3818">tryAcquire&#21152;&#38145;&#25104;&#21151;&#65311;</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="14" x="286" y="760.9795">no</text><polygon fill="#F1F1F1" points="161,649.2026,274,649.2026,286,661.2026,274,673.2026,161,673.2026,149,661.2026,161,649.2026" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="21" x="221.5" y="683.4131">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="113" x="161" y="665.0107">node.prev == head</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="14" x="286" y="658.6084">no</text><polygon fill="#F1F1F1" points="217.5,930.4604,229.5,942.4604,217.5,954.4604,205.5,942.4604,217.5,930.4604" style="stroke:#181818;stroke-width:0.5;"/><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="116" x="159.5" y="974.4604"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="96" x="169.5" y="995.5991">&#32447;&#31243;&#36827;&#20837;&#38459;&#22622;&#29366;&#24577;</text><polygon fill="#F1F1F1" points="217.5,605.2026,229.5,617.2026,217.5,629.2026,205.5,617.2026,217.5,605.2026" style="stroke:#181818;stroke-width:0.5;"/><polygon fill="#F1F1F1" points="201,1028.4292,234,1028.4292,246,1040.4292,234,1052.4292,201,1052.4292,189,1040.4292,201,1028.4292" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="33" x="201" y="1044.2373">&#27515;&#24490;&#29615;</text><line style="stroke:#181818;stroke-width:1.0;" x1="102" x2="102" y1="334.7495" y2="357.2651"/><polygon fill="#181818" points="98,347.2651,102,357.2651,106,347.2651,102,351.2651" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="102" x2="102" y1="391.2339" y2="411.2339"/><polygon fill="#181818" points="98,401.2339,102,411.2339,106,401.2339,102,405.2339" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="102" x2="102" y1="276.3784" y2="300.7808"/><polygon fill="#181818" points="98,290.7808,102,300.7808,106,290.7808,102,294.7808" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="151" x2="188" y1="264.3784" y2="264.3784"/><polygon fill="#181818" points="184,355.2651,188,365.2651,192,355.2651,188,359.2651" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="188" x2="188" y1="264.3784" y2="455.2339"/><line style="stroke:#181818;stroke-width:1.0;" x1="188" x2="102" y1="455.2339" y2="455.2339"/><line style="stroke:#181818;stroke-width:1.0;" x1="102" x2="102" y1="455.2339" y2="475.2339"/><polygon fill="#181818" points="98,465.2339,102,475.2339,106,465.2339,102,469.2339" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="102" x2="102" y1="217.3784" y2="252.3784"/><polygon fill="#181818" points="98,242.3784,102,252.3784,106,242.3784,102,246.3784" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="102" x2="102" y1="159.0073" y2="183.4097"/><polygon fill="#181818" points="98,173.4097,102,183.4097,106,173.4097,102,177.4097" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="163.5" x2="210" y1="147.0073" y2="147.0073"/><polygon fill="#181818" points="206,327.2651,210,337.2651,214,327.2651,210,331.2651" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="210" x2="210" y1="147.0073" y2="487.2339"/><line style="stroke:#181818;stroke-width:1.0;" x1="210" x2="114" y1="487.2339" y2="487.2339"/><polygon fill="#181818" points="124,483.2339,114,487.2339,124,491.2339,120,487.2339" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="317.5" x2="317.5" y1="168.9761" y2="203.9761"/><polygon fill="#181818" points="313.5,193.9761,317.5,203.9761,321.5,193.9761,317.5,197.9761" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="317.5" x2="317.5" y1="237.9448" y2="272.9448"/><polygon fill="#181818" points="313.5,262.9448,317.5,272.9448,321.5,262.9448,317.5,266.9448" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="102" x2="102" y1="103.2969" y2="135.0073"/><polygon fill="#181818" points="98,125.0073,102,135.0073,106,125.0073,102,129.0073" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="102" x2="102" y1="499.2339" y2="519.2339"/><polygon fill="#181818" points="98,509.2339,102,519.2339,106,509.2339,102,513.2339" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="317.5" x2="317.5" y1="103.2969" y2="135.0073"/><polygon fill="#181818" points="313.5,125.0073,317.5,135.0073,321.5,125.0073,317.5,129.0073" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="173.5" x2="256" y1="91.2969" y2="91.2969"/><polygon fill="#181818" points="246,87.2969,256,91.2969,246,95.2969,250,91.2969" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="217.5" y1="30" y2="64.2969"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="102" y1="64.2969" y2="64.2969"/><line style="stroke:#181818;stroke-width:1.0;" x1="102" x2="102" y1="64.2969" y2="79.2969"/><polygon fill="#181818" points="98,69.2969,102,79.2969,106,69.2969,102,73.2969" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="379" x2="393" y1="91.2969" y2="91.2969"/><line style="stroke:#181818;stroke-width:1.0;" x1="393" x2="393" y1="91.2969" y2="519.2339"/><polygon fill="#181818" points="389,509.2339,393,519.2339,397,509.2339,393,513.2339" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="102" x2="393" y1="519.2339" y2="519.2339"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="217.5" y1="519.2339" y2="551.2339"/><polygon fill="#181818" points="213.5,541.2339,217.5,551.2339,221.5,541.2339,217.5,545.2339" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="217.5" y1="833.9448" y2="866.4604"/><polygon fill="#181818" points="213.5,856.4604,217.5,866.4604,221.5,856.4604,217.5,860.4604" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="217.5" y1="775.5737" y2="799.9761"/><polygon fill="#181818" points="213.5,789.9761,217.5,799.9761,221.5,789.9761,217.5,793.9761" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="286" x2="298" y1="763.5737" y2="763.5737"/><polygon fill="#181818" points="294,832.4604,298,842.4604,302,832.4604,298,836.4604" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="298" x2="298" y1="763.5737" y2="910.4604"/><line style="stroke:#181818;stroke-width:1.0;" x1="298" x2="217.5" y1="910.4604" y2="910.4604"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="217.5" y1="910.4604" y2="930.4604"/><polygon fill="#181818" points="213.5,920.4604,217.5,930.4604,221.5,920.4604,217.5,924.4604" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="217.5" y1="731.5737" y2="751.5737"/><polygon fill="#181818" points="213.5,741.5737,217.5,751.5737,221.5,741.5737,217.5,745.5737" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="217.5" y1="673.2026" y2="697.605"/><polygon fill="#181818" points="213.5,687.605,217.5,697.605,221.5,687.605,217.5,691.605" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="286" x2="316.5" y1="661.2026" y2="661.2026"/><polygon fill="#181818" points="312.5,791.9761,316.5,801.9761,320.5,791.9761,316.5,795.9761" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="316.5" x2="316.5" y1="661.2026" y2="942.4604"/><line style="stroke:#181818;stroke-width:1.0;" x1="316.5" x2="229.5" y1="942.4604" y2="942.4604"/><polygon fill="#181818" points="239.5,938.4604,229.5,942.4604,239.5,946.4604,235.5,942.4604" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="217.5" y1="954.4604" y2="974.4604"/><polygon fill="#181818" points="213.5,964.4604,217.5,974.4604,221.5,964.4604,217.5,968.4604" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="217.5" y1="629.2026" y2="649.2026"/><polygon fill="#181818" points="213.5,639.2026,217.5,649.2026,221.5,639.2026,217.5,643.2026" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="246" x2="340.5" y1="1040.4292" y2="1040.4292"/><polygon fill="#181818" points="336.5,846.4604,340.5,836.4604,344.5,846.4604,340.5,842.4604" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="340.5" x2="340.5" y1="617.2026" y2="1040.4292"/><line style="stroke:#181818;stroke-width:1.0;" x1="340.5" x2="229.5" y1="617.2026" y2="617.2026"/><polygon fill="#181818" points="239.5,613.2026,229.5,617.2026,239.5,621.2026,235.5,617.2026" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="217.5" y1="1008.4292" y2="1028.4292"/><polygon fill="#181818" points="213.5,1018.4292,217.5,1028.4292,221.5,1018.4292,217.5,1022.4292" style="stroke:#181818;stroke-width:1.0;"/><line style="stroke:#181818;stroke-width:1.0;" x1="217.5" x2="217.5" y1="585.2026" y2="605.2026"/><polygon fill="#181818" points="213.5,595.2026,217.5,605.2026,221.5,595.2026,217.5,599.2026" style="stroke:#181818;stroke-width:1.0;"/><!--SRC=[bLB1Ji905BptA_RONenUInf3_0I_e955cf22xQhX9XWCBO96YH8b0XeJWe340oYLyZFiBfpy1RlRKX3ZmSlcPJAPcJTlJQGQIDWtKeTfW8nCTE_WK3EWA0bQ78ZpIfRKshF75s_0lJjW8XL1HTdSbW1AG5tCG5CI061KKhDmVZ1rRkXeGbj5qdt2jHOfNyshzO2ifnWN07adkZlhkNJSutBJzv6lJkq1ESb6E8SfXZHIkCHsVSsJA-7nDRPAlgFFzTHeiODB3H-CX4oxmPRXIWlGHAaq7s7IX23C1_MO5XSMQ63dWup3SPPlrHmFtwXpGSwzkYpFvsTKcU_f9TXYph-Yy1Y-llS2VWf19aF78-92dtOjxEQz6d7XbhrzDo8OC0rL53Ilfs9m8st08w0e807Ls7fHCZuhaKvprZ-bbTRgZPTTBz7LT5-VzJzBdzavcli8IsU-_-hLHnUO7DnmSe_pp_EgWviFY-_WxmgE4reIYgJhOBTDow_IDm00]--></g></svg>

<p>有一点需要注意，即使<code>ReentrantLock</code>构造时<code>fair</code>设置为true，使用不带超时的<code>tryLock()</code>加锁时也会使用非公平锁的策略。</p>
<h2 id="非公平锁加锁"><a href="#非公平锁加锁" class="headerlink" title="非公平锁加锁"></a>非公平锁加锁</h2><p>调用链路：<code>ReentrantLock#lock()</code> &rarr; <code>ReentrantLock.NonfairSync#lock()</code> 。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 【ReentrantLock.java】</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">NonfairSync</span> <span class="keyword">extends</span> <span class="title class_">Sync</span> &#123;</span><br><span class="line">        ......</span><br><span class="line">        <span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">lock</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (compareAndSetState(<span class="number">0</span>, <span class="number">1</span>)) <span class="comment">//直接使用CAS加锁，加锁成功后设置为独占线程</span></span><br><span class="line">                setExclusiveOwnerThread(Thread.currentThread());</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                acquire(<span class="number">1</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">protected</span> <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">tryAcquire</span><span class="params">(<span class="type">int</span> acquires)</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> nonfairTryAcquire(acquires);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">// 【AbstractQueuedSynchronizer.java】</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">acquire</span><span class="params">(<span class="type">int</span> arg)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (!tryAcquire(arg) &amp;&amp; <span class="comment">//调用NonfairSync.tryAcquire()</span></span><br><span class="line">            acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) <span class="comment">//acquireQueued与公平锁流程相同</span></span><br><span class="line">            selfInterrupt();</span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">// 【ReentrantLock.java】</span></span><br><span class="line">        <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">nonfairTryAcquire</span><span class="params">(<span class="type">int</span> acquires)</span> &#123;</span><br><span class="line">            <span class="keyword">final</span> <span class="type">Thread</span> <span class="variable">current</span> <span class="operator">=</span> Thread.currentThread();</span><br><span class="line">            <span class="type">int</span> <span class="variable">c</span> <span class="operator">=</span> getState();</span><br><span class="line">            <span class="keyword">if</span> (c == <span class="number">0</span>) &#123; <span class="comment">//当前是未锁定转台</span></span><br><span class="line">                <span class="comment">//直接尝试加锁，不会判断队列中是否有其他线程排队，而公平锁会首先判断队列中是否已经有其他线程在排队</span></span><br><span class="line">                <span class="keyword">if</span> (compareAndSetState(<span class="number">0</span>, acquires)) &#123;</span><br><span class="line">                    setExclusiveOwnerThread(current);</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (current == getExclusiveOwnerThread()) &#123; <span class="comment">//锁重入</span></span><br><span class="line">                <span class="type">int</span> <span class="variable">nextc</span> <span class="operator">=</span> c + acquires;</span><br><span class="line">                <span class="keyword">if</span> (nextc &lt; <span class="number">0</span>) <span class="comment">// overflow</span></span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&quot;Maximum lock count exceeded&quot;</span>);</span><br><span class="line">                setState(nextc);</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br></pre></td></tr></table></figure>

<p>从代码可以看出，公平锁和非公平锁的加锁流程几乎相同，区别是state==0时，非公平锁会直接使用CAS尝试加锁，而公平锁会首先判断等待队列中是否有其他线程在排队，如果没人在排队才会使用CAS加锁。</p>
<h2 id="释放锁"><a href="#释放锁" class="headerlink" title="释放锁"></a>释放锁</h2><p>公平锁和非公平锁释放锁的流程是一样的。调用链路<code>ReentrantLock#unlock()</code> &rarr; <code>AbstractQueuedSynchronizer#release()</code>。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 【AbstractQueuedSynchronizer.java】</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">release</span><span class="params">(<span class="type">int</span> arg)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (tryRelease(arg)) &#123;</span><br><span class="line">            <span class="type">Node</span> <span class="variable">h</span> <span class="operator">=</span> head;</span><br><span class="line">            <span class="keyword">if</span> (h != <span class="literal">null</span> &amp;&amp; h.waitStatus != <span class="number">0</span>)</span><br><span class="line">                unparkSuccessor(h); <span class="comment">//唤醒队列中下一个等待线程</span></span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 【ReentrantLock.java】</span></span><br><span class="line">        <span class="keyword">protected</span> <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">tryRelease</span><span class="params">(<span class="type">int</span> releases)</span> &#123;</span><br><span class="line">            <span class="comment">// 获取state并减一</span></span><br><span class="line">            <span class="type">int</span> <span class="variable">c</span> <span class="operator">=</span> getState() - releases;</span><br><span class="line">            <span class="comment">// 加锁和解锁线程如果不同就会抛出异常</span></span><br><span class="line">            <span class="keyword">if</span> (Thread.currentThread() != getExclusiveOwnerThread())</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalMonitorStateException</span>();</span><br><span class="line">            <span class="type">boolean</span> <span class="variable">free</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line">            <span class="keyword">if</span> (c == <span class="number">0</span>) &#123; <span class="comment">//为0表示锁被释放，否则，表示锁的多次重入</span></span><br><span class="line">                free = <span class="literal">true</span>;</span><br><span class="line">                setExclusiveOwnerThread(<span class="literal">null</span>); <span class="comment">//独占线程设置为null</span></span><br><span class="line">            &#125;</span><br><span class="line">            setState(c); <span class="comment">//更新锁状态state</span></span><br><span class="line">            <span class="keyword">return</span> free;</span><br><span class="line">        &#125;</span><br></pre></td></tr></table></figure>

    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/Java/" rel="tag"># Java</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/posts/32780962.html" rel="prev" title="PlantUML样式指南">
                  <i class="fa fa-angle-left"></i> PlantUML样式指南
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/posts/48a4fa29.html" rel="next" title="Handler源码解析">
                  Handler源码解析 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 
    <span itemprop="copyrightYear">2024</span>
    <span class="with-love">
      <i class="fa fa-heart"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">Jason</span>
  </div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener external nofollow noreferrer" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/pisces/" rel="noopener external nofollow noreferrer" target="_blank">NexT.Pisces</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/next-theme-pjax/0.6.0/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.24/fancybox/fancybox.umd.js" integrity="sha256-oyhjPiYRWGXaAt+ny/mTMWOnN1GBoZDUQnzzgC7FRI4=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/pjax.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>


  <script class="next-config" data-name="mermaid" type="application/json">{"enable":true,"theme":{"light":"default","dark":"dark"},"js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.5.0/mermaid.min.js","integrity":"sha256-K7oJiQlDulzl24ZUFOywuYme1JqBBvQzK6m8qHjt9Gk="}}</script>
  <script type="module" src="/js/zenuml-definition-074a43fa.js"></script>
  <script type="module" src="/js/mermaid-zenuml.esm.min.mjs"></script>
  <script src="/js/third-party/tags/mermaid.js"></script>


  <script src="/js/third-party/fancybox.js"></script>



  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>



</body>
</html>
